#include "stm32f10x.h"
#include "I2C_Hard.h"
#include "OLED_Font.h"


const static uint8_t slave_address = 0x78;

void write_command_n_byte(uint8_t* command_data,uint8_t command_data_length){
    
    uint8_t write_command_and_command[command_data_length+1];
    
    write_command_and_command[0] = 0x00;
    
    for(uint8_t i=0;i<command_data_length;i++){
    
        write_command_and_command[i+1] = command_data[i];
    }
    send_n_byte(slave_address,write_command_and_command,command_data_length+1);

}

void write_single_command(uint8_t command){

    write_command_n_byte(&command,1);
}

void write_data(const uint8_t * data,const uint8_t data_length){

    uint8_t write_data_and_data[data_length+1];
    
    write_data_and_data[0] = 0x40;
    
    for(uint8_t i=0;i<data_length;i++){
    
        write_data_and_data[i+1] = data[i];
    }
    
    send_n_byte(slave_address,write_data_and_data,data_length+1);
}

void clear_screen(void){

// 水平扫描模式
	write_command_n_byte((uint8_t[]){0x20,0x00},2);
   
	
	/* 设置行的范围 设定为从第一行到第64行
	
	*/
	write_command_n_byte((uint8_t[]){0x22,0,7},3);
	
	/* 设置列的范围 设定为从第一列到第128列
		
	*/
	write_command_n_byte((uint8_t[]){0x21,0,127},3);
    
    // 因为在 while 中单次发送16字节的数据，所以这里要除以16
    uint16_t count = 128*8/16; 
    
    uint8_t blank_byte[] = {
        
        0,0,0,0,
        0,0,0,0,
        0,0,0,0,
        0,0,0,0,
    };
    
    while(count>0){
    
        write_data(blank_byte,16);
        count--;
    }
	
}

void init_oled(void){


       
    write_single_command(0xAE);	//关闭显示
    
	write_single_command(0xD5); //设置显示时钟分频比/振荡器频率
	write_single_command(0x80);
    
	write_single_command(0xA8); //设置多路复用率
	write_single_command(0x3F);
    
	write_single_command(0xD3); //设置显示偏移
	write_single_command(0x00);
    
	write_single_command(0x40); //设置显示开始行
    
	write_single_command(0xA1); //设置左右方向，0xA1正常 0xA0左右反置
    
	write_single_command(0xC8); //设置上下方向，0xC8正常 0xC0上下反置
    
	write_single_command(0xDA); //设置COM引脚硬件配置
	write_single_command(0x12);
    
	write_single_command(0x81); //设置对比度控制
	write_single_command(0xCF);
    
	write_single_command(0xD9); //设置预充电周期
	write_single_command(0xF1);
    
	write_single_command(0xDB); //设置VCOMH取消选择级别
	write_single_command(0x30);
    
	write_single_command(0xA4); //设置整个显示打开/关闭
    
	write_single_command(0xA6); //设置正常/倒转显示
    
	write_single_command(0x8D); //设置充电泵
	write_single_command(0x14);
	write_single_command(0x2E); //关闭滚动
	write_single_command(0xAF); //开启显示

    clear_screen();

}



void show_fixed_length_string(const uint8_t row,const uint8_t column,const uint8_t * str,const uint8_t fixed_string_length){


	// 水平扫描模式
	write_command_n_byte((uint8_t[]){0x20,0x00},2);

	/* 每一个字的高度为16个像素，宽度为8个像素
		oled 高 64 个像素，宽 128个像素
	因为 高度只能设置为 0-7 ，
	64/8=8 每传送一个字节的数据刚好 能填充一列的8个像素
	传送8个字节刚好能填充屏幕的一整列
	
	
	*/
	
	/* 设置行的范围 高16个像素，也就是每传完2个字节就要把指针重定向到第一行
	
	*/
	write_command_n_byte((uint8_t[]){0x22,row*2,row*2+2},3);
	
	/* 设置列的范围 宽8个像素
		
	*/
	write_command_n_byte((uint8_t[]){0x21,column*8,column*8+8*fixed_string_length},3);
	

	const uint8_t * temp = str;
    

    
	for(uint8_t i=0;i<fixed_string_length;i++){
	
		// asc2 表中 前32个都是控制字符
		// 字体库是从 第33个字符开始的
		const uint8_t * f = OLED_F8x16[*temp - 32];
		
		// 因为是水平扫描模式，且一个字符占两行
		// 所以打印字符串的时候，要先把第一行（字符的上半部分）先打印
		// 然后再把指针跳转到第二行，第二行显示字符的下半部分
		// 前8个字符为上半部分
        
		write_data(f,8);
		temp++;
	}
	
	temp = str;
	

	for(uint8_t i=0;i<fixed_string_length;i++){
	
		// asc2 表中 前32个都是控制字符
		// 字体库是从 第33个字符开始的
		const uint8_t * f = OLED_F8x16[*temp - 32];
		
		// 显示后8个字符为 字符的下半部分
        
     
        
		write_data(f+8,8);
		temp++;
	}

}

void show_string(const uint8_t row,const uint8_t column,const uint8_t * str){
	
	const uint8_t * ch = str;
	
	uint8_t length=0;
	while(*ch != 0 ){
		length++;
		ch++;
	}
	
    show_fixed_length_string(row,column,str,length);    
}	

